.. _Литералы:

Литералы
========

.. index::
    literal
    литерал


Программы выполняют свои задачи, манипулируя значениями переменных и объектов.
Они создают новые значения и новые объекты, используя их с функциями и операторами.
Некоторые значения необязательно создавать во время выполнения программы;
вместо этого они записываются непосредственно в исходный код. Например,
значение с плавающей запятой 0.75 и приведенное ниже строковое значение "Общая цена:" не рассчитываются
программой:

.. code-block:: d

    discountedPrice = actualPrice * 0.75;
    totalPrice += count * discountedPrice;
    writeln("Total price: ", totalPrice);

Такие значения, которые вводятся непосредственно в исходный код, называются литералами. Мы
использовали много литералов в программах, которые мы написали


Целочисленные литералы
----------------------

.. index::
  Целочисленные литералы

Целочисленные литералы могут быть записаны одним из четырех способов: десятичной системой, которую мы используем
в повседневной жизни; шестнадцатеричной и двоичной системами, которые больше подходят
для определенных вычислительных задач; и восьмеричной системой, которая может понадобиться в оченьредких случаях.
Чтобы сделать код более читабельным, можно вставить символы _ в любом месте после первой цифры целочисленных литералов.
Например, мы можем использовать это для формирования групп из трех цифр, как в 1_234_567 . Другим примером было бы, если бы мы
измерили некоторое значение валюты в центах и использовали его для разделения валюты
единицы измерения из центов, как в 199_99 . Эти символы необязательны; они игнорируются
компилятором

**В десятичной систем**: Литералы задаются десятичными цифрами
точно так же, как мы привыкли в нашей повседневной жизни, например, 12. При использовании
десятичной системы первая цифра не может быть 0 . Такая начальная нулевая цифра
часто используется в других языках программирования для обозначения восьмеричной системы, поэтому это
ограничение помогает предотвратить ошибки, вызванные этим легко упускаемым
из виду различием. Это не исключает 0 само по себе: 0 равно нулю.

**шестнадцатеричной системе** : Литералы начинаются с 0x или 0XX и включают
цифры шестнадцатеричной системы: "0123456789abcdef" и "ABCDEF", как в
0x12ab00fe .

**В восьмеричной системе**: литералы задаются с использованием восьмеричного шаблона из
модуля std.conv и включают цифры восьмеричной системы: "01234567", как
в восьмеричной octal!576

*В двоичной системе*: Литералы начинаются с 0b или 0BB и включают цифры
двоичной системы: 0 и 1 , как в 0b01100011 .

**Типы целочисленных литералов**

Как и любое другое значение, каждый литерал имеет определенный тип. Типы литералов
не указаны явно как int , double и т.д. Компилятор выводит тип из
значения и синтаксиса самого литерала.
Хотя в большинстве случаев типы литералов не важны, иногда
типы могут не соответствовать выражениям, в которых они используются. В таких случаях
тип должен быть указан явно.

По умолчанию предполагается, что целочисленные литералы имеют тип int . Когда значение
оказывается слишком большим, чтобы быть представленным int, компилятор использует
следующую логику для определения типа литерала:

* Если значение литерала не соответствует int и оно указано в десятичной
  системе счисления, то его тип - long .
* Если значение литерала не соответствует int и оно указано в любой другой
  системе, то тип становится первым из следующих типов, которые могут
  вместить значение: uint , long и ulong .

Чтобы увидеть эту логику в действии, давайте попробуем следующую программу, которая использует преимущества
type of и stringof :

.. code-block:: d

    import std.stdio;

    void main()
    {
        writeln("\n--- these are written in decimal ---"); // fits an int, so the type is int
        writeln(2_147_483_647, "\t\t", typeof(2_147_483_647).stringof); // does not fit an int and is decimal, so the type is long
        writeln(2_147_483_648, "\t\t", typeof(2_147_483_648).stringof);
        writeln("\n--- these are NOT written in decimal ---"); // fits an int, so the type is int
        writeln(0x7FFF_FFFF, "\t\t", typeof(0x7FFF_FFFF).stringof); // does not fit an int and is not decimal, so the type is uint
        writeln(0x8000_0000, "\t\t", typeof(0x8000_0000).stringof); // does not fit a uint and is not decimal, so the type is long
        writeln(0x1_0000_0000, "\t\t", typeof(0x1_0000_0000).stringof); // does not fit a long and is not decimal, so the type is ulong
    }


.. code-block:: console

    --- в десятичной системе ---
    2147483647 int
    2147483648 long
    --- не в десятичной
    2147483647 int
    2147483648 uint
    4294967296  long
    9223372036854775808 ulong

**Суффикс L и U**

Независимо от величины значения, если оно заканчивается на L, как в 10L , тип long .
Если литерал заканчивается на U, как в 10U , то его тип является типом без знака. Также можно использовать строчную букву u.

Спецификаторы L и U можно использовать вместе в любом порядке. Например, 7UL и
8LU оба относятся к типу ulong .

Литералы с плавающей точкой
----------------------------

.. index::
  литералы с плавающей точкой

Литералы с плавающей запятой могут быть указаны либо в десятичной системе, как в
1.234 , либо в шестнадцатеричной системе, как в 0x9a.bc .
**В десятичной системе:** Показатель степени может быть добавлен после символа e или
E , что означает "умножить на 10 в степени". Например, 3.4e5 означает "3,4 умножить на 10 в
степени 5", или 340000.
Символ -, введенный перед значением показателя степени, изменяет значение на
"разделить на 10 в степени". Например, 7,8e-3 означает "7,8, деленное на 10
в степени 3". Символ + также может быть указан перед значением параметра
показатель степени, но это не имеет никакого эффекта. Например, 5.6e2 и 5.6e+2 - это одно и то же.
**В шестнадцатеричной системе:** Значение начинается либо с 0x, либо с 0X, а части
до и после точки указаны цифрами шестнадцатеричной
системы. Поскольку e и E являются допустимыми числами в этой системе, показатель степени указывается
через p или P .
Другое отличие заключается в том, что показатель степени означает не "10 в степени",
а "2 в степени". Например, часть P4 в 0xabc.defP4 означает "2 в
степени 4".
Литералы с плавающей запятой почти всегда имеют точку, но она может быть опущена, если
указан показатель степени. Например, 2e3 - это литерал с плавающей запятой со значением
2000.
Значение перед точкой может быть опущено, если оно равно нулю. Например, .25 - это литерал, имеющий значение "четверть".
Необязательные символы _ также могут использоваться с литералами с плавающей запятой, как в 1_000.5 .

**Типы литералов с плавающей запятой**

Если явно не указано, тип литерала с плавающей запятой - double . Спецификаторы f и
F означают float , а спецификатор L означает real . Например; 1.2 -
двойное значение , 3.4f - плавающее , а 5.6L - реальное .

Символьные литералы
--------------------

.. index::
  cимвольные литералы

Символьные литералы указываются в одинарных кавычках, как в 'a', '\n', '\x21' и т.д.
**Как сам символ:** Символ может быть введен непосредственно с клавиатуры или
скопирован из отдельного текста: 'a', 'ş' и т.д.
**В качестве спецификатора символа:** Символьный литерал может быть задан символом обратной косой
черты, за которым следует специальный символ. Например, сам символ обратной косой
черты может быть указан с помощью '\\' . Принимаются следующие спецификаторы символов:

.. list-table:: Title
   :widths: 25 50
   :header-rows: 1
   :align: center

   * - Синтаксис
     - Значение
   * - \'
     - одинарная кавычка
   * - \"
     -  двойные кавычки
   * - \?
     - знак вопроса
   * - \a
     - звук (тревога)
   * - \b
     - удалить символ
   * - \f
     - новая страница
   * - \n
     - новая строка
   * - \r
     - возврат каретки
   * - \t
     - табуляция
   * - \v
     - вертикальная табуляция

**Как расширенный код символа ASCII:** Символьные литералы также могут быть заданы
их кодами. Коды могут быть заданы либо в шестнадцатеричной, либо в
восьмеричной системе счисления. При использовании шестнадцатеричной системы литерал должен начинаться с \x
и содержать две цифры для кода, а при использовании восьмеричной системы литерал
должен начинаться с \ и содержать до трех цифр. Например, литералы '\x21' и
'\41' оба являются восклицательным знаком.

**Как код символа Unicode:** когда литерал указан с u, за которым следуют
4 шестнадцатеричные цифры, тогда его тип - wchar . Когда он указан с U, за которым следуют
8 шестнадцатеричных цифр, тогда его тип - dchar . Например, '\u011e' и
'\U0000011e' оба являются символом G, имеющими тип char и dchar
соответственно.

**Как именованная символьная сущность:** Символы, у которых есть имена сущностей, могут быть указаны
с помощью этого имени, используя синтаксис символьной сущности HTML '\&name;' . D поддерживает все символьные сущности
из HTML 5 . Например, '\&euro;' - это €, '\&hearts;' - это ??? ,а '\&copy;' - это ©.

Строковые литералы
------------------

.. index::
  строковые литералы

Строковые литералы могут быть определены различными способами

**Строковые литералы в двойных кавычках**

Наиболее распространенным способом указания строковых литералов является ввод их символов
в двойных кавычках, как в "hello". Отдельные символы строковых литералов следуют
правилам символьных литералов. Например, литерал "A4 ka\
u011fıt: 3\&frac12;TL" совпадает с "A4 kağıt: 3½TL" .

**Строковые литералы в обратных кавычках (Wysiwyg)**

Когда строковые литералы задаются с использованием обратных кавычек, отдельные символы
строки не подчиняются специальным правилам синтаксиса символьных литералов. Например,
литерал `c:\nurten` может быть именем каталога в операционной системе Windows.
Если бы оно было написано с использованием двойных кавычек, часть "\n" означала бы символ новой строки

.. code-block:: d

    writeln(`c:\nurten`);
    writeln("c:\nurten");

Вывод

.. code-block:: console

    c:\nurten  -
    c:
    urten

Строковые литералы Wysiwyg в качестве альтернативы могут быть указаны с использованием двойных кавычек, но
с добавлением символа r: r"c:\nurten" также является строковым литералом wysiwyg.


**Строковые литералы с разделителями**

Строковый литерал может содержать разделители, которые вводятся непосредственно внутри двойного
цитаты. Эти разделители не считаются частями значения литерала.
Строковые литералы с разделителями начинаются с q перед открывающей двойной кавычкой.
Например, значение q".hello." равно "привет"; точки не являются частями значения.
Если оно заканчивается новой строкой, разделитель может содержать более одного символа:


.. code-block:: d

    writeln(q"MY_DELIMITER
              first line
              second line
              MY_DELIMITER");

MY_DELIMITER не является частью литерала

.. code-block:: console

    first line
    second line

Такой многострочный строковый литерал, включающий все отступы, называется heredoc.

**Типы строковых литералов**

По умолчанию типом строкового литерала является неизменяемый(char)[] . Добавленный символ c , w или
d явно указывает тип строки как неизменяемый(char)[] ,
неизменяемый(wchar)[] или неизменяемый(dchar)[] соответственно. Например,
символы "hello"d имеют тип immutable(dchar) .
Мы видели в главе "Строки" (стр. 75), что эти три типа строк имеют
псевдонимы string , wstring и string , соответственно.

Литералы вычисляемые во время компиляции
-----------------------------------------

Литералы можно указывать в виде выражений. Например, вместо того, чтобы записывать
общее количество секунд в январе как 2678400 или 2_678_400 , можно
указать его с помощью терминов, составляющих это значение, а именно 60 * 60 * 24 * 31 . Операции
умножения в этом выражении не влияют на скорость
выполнения программы; программа компилируется так, как если бы вместо нее было записано 2678400.
То же самое относится и к строковым литералам. Например, операция объединения в
"hello" ~ "world" выполняется во время компиляции, а не во время выполнения. Программа
компилируется так, как если бы код содержал единственный строковый литерал "hello world" .


Упражнения
-----------
#. Следующая строка вызывает ошибку компиляции:
   int amount = 10_000_000_000; // ← ОШИБКА компиляции
   Измените программу так, чтобы строка могла быть скомпилирована, и эта сумма равнялась
   десяти миллиардам.
#. Напишите программу, которая увеличивает значение переменной и печатает его
   непрерывно. Сделайте так, чтобы значение всегда печаталось в одной и той же строке, перезаписывая
   предыдущее значение:
   Число: 25774 ← всегда в одной и той же строке
   Здесь может быть полезен специальный символьный литерал, отличный от '\n'.
